Skip to content

fix(auth): contain destructive identity consolidation - #7459

Merged
bokelley merged 6 commits into
mainfrom
fix/6827-identity-containment
Sep 17, 2026
Merged

bokelley merged 6 commits into
mainfrom
fix/6827-identity-containment

Conversation

@bokelley

@bokelley bokelley commented Sep 13, 2026 •

Copy link
Copy Markdown
Contributor

Contain destructive generic identity consolidation while retaining the authenticated-credential administrator authority landed in #7450 and #7452. This remains containment for #6827, not closure. Generic consolidation and automatic replacement-primary promotion remain refused.

Confirmed provider deletion uses the existing durable audit store, sorted credential/identity locks, exact-cardinality revocation, and a terminal lifecycle recheck. Missing-primary survivors require manual recovery; no replacement primary is inferred. Cookie, Bearer, and MCP admission/cache hits require a current primary-database credential lifecycle snapshot. Provider writes without a durable intent journal remain deferred. Local transactional rollback and next-hit lifecycle denial do not guarantee provider/local consistency, distributed cache pub/sub, or cancellation of already admitted requests.

Replacement qualification

  • Qualified main base: cfc33f6448a6e0ded4afd71c72d501398c346cdb. Initially verified base c9a8c4f91b056aea6871c76c80e9afe307971ffa is the fix(auth): authorize web admins by authenticated credential #7452 squash with parent f928b36ff4f721ae64c73cc5f80de65b3d69a071. Main advanced once during the mandatory hook through fix(protocol): align 3.2 error recovery compatibility #7570; its 17 paths have zero PR overlap and were independently reviewed.
  • Replacement head: 9fa7707c828be7d75dd1c41b12a1549121f1010e; final tree and independently computed merge tree: 74e47c4e36fa58fc5d87a0d120d91491523c2d8a.
  • Replaced published-head lease: c5873d64b1a3d20833671618aa178c250cf8dee4. Published under this explicit force-with-lease after rechecking the unchanged qualified base, original remote head, Draft state, auto-merge off, and clean exact candidate. Normal pre-push version-sync and changeset-scope checks passed; the normal hook correctly found no storyboard or documentation scope.
  • Six commits retain original order, authors, author dates, and messages. The unmodified exact replay was attempted first and stopped at commit 5 with four textual conflicts. It is not described as a patch-identical pure replay. Original commits 1–4 and 6 retain their stable patch IDs; commit 5 contains the explicit compatibility correction below.
  • After correction on the initially verified base, all six commits replayed onto the advanced base with six equal range-diff entries, equal per-commit stable patch IDs, all 43 PR result blobs identical, and a byte-identical cumulative binary diff. An independent reconstruction from the original base/head, explicit conflict resolutions, three-file test delta, and non-overlapping upstream delta yields the final tree above.
  • Effective diff: 43 files, +5,529/−2,031. Ordinary diff (core.abbrev=10): 425,444 bytes, SHA-256 06a7f07163f65cbc07c0a66122315f9e50f49be5a7694a54964af16261e5e73f. Binary/full-index diff: 428,024 bytes, SHA-256 63f05c44007d95ed37b5dd5aebd6f451b095996177a314dd98b66b21e57a7a44. Aggregate stable patch ID: c276c0b8621f58e4fa0b05c74e1edc1a4a551456 (original: 6dcd3cbfcff77f1c9ed21cea073a1166d11608e4).

Explicit compatibility delta

Nine paths overlap upstream: the two Addie admin lookup modules; working-group DB; HTTP; auth middleware; and the aao-admin-status, addie-admin-global-auth, network-health-security, and working-group-admin-global-auth test files.

The parent's two production admin lookup modules are retained byte-for-byte. Main removes both positive and negative authorization caches and preserves typed outage handling; it subsumes the child's older positive-cache removal. The other production overlaps retain both parent exact-credential/reserved-admin boundaries and child lifecycle fences. All non-overlap production blobs remain identical to the reviewed child.

The textual checkpoint exposed two tests calling cache getters removed by #7450. The only subsequent deliberate delta is three test files, +52/−5, folded into original commit 5: replace the removed web cache assertion with observable same-module grant-to-revocation behavior; remove the obsolete Slack cache getter assertion while retaining live DB before/after authorization, quarantine, and replay assertions; add four cold/warm route regressions for oppositely privileged linked credentials and terminal/missing-primary administrator sessions. No production containment is weakened, and no new migration, dependency, changeset, or protocol delta is introduced by this PR.

Local validation and review

  • Fresh exact-lock Docker install: 1,572 installed packages, zero version drift. Package/dependency declarations and lock match the qualified base. The live npm audit reports 15 inherited advisories (4 moderate, 11 high); this is not a zero-advisory installation. GitHub Dependency Review is a separate exact-head gate for PR dependency findings.
  • Final exact-tree focused qualification: 2,306/2,306 tests across 158 files, zero failures or skips, against a fresh isolated PostgreSQL database. Overlapping scopes include all 24 changed files / 279 tests, all 40 predecessor files / 907 tests, and 134 implicated identity/WorkOS/session/authorization/invariant files / 1,804 tests. Final-tree upstream error-recovery/transport vectors 99/99, both TypeScript phases, migrations 3/3, and dynamic-import checks 7/7 also pass.
  • Exactly one normal full commit hook passed for the deliberate correction: 1,063/1,063 root tests across 71 files; 9,985 passed and 31 expected skips across 635 server unit files, zero failures; dynamic imports 7/7, format identity 1/1, callapi state changes 10/10, and both TypeScript checks passed. It ran on the corrected original commit 5 before the subsequent content-preserving main refresh. Counts overlap the focused suites and are not additive.
  • Migration registry 3/3 and duplicate-allocation proof: all 576 SQL migrations, maximum allocation 598, and migration tree be6336113c9b2db393b6c3a0550bc72f727c9955 equal main. No PR allocation. Addie tool reference/inventory and portability checks pass (249 tools, 69 sets).
  • Independent read-only security/composition review approved the exact base/head/tree above with zero Must Fix and zero Should Fix findings. The reviewer independently rehashed the complete final Git tree and checked all ancestry, patch, overlap, blob, and migration proofs.

Initial published-head CI qualification

Sixteen checks passed before Ready, including both database migration smoke tests, duplicate allocations, Dependency Review, Semgrep, GitGuardian, web build/tests, and three canonical shards. The exact base-to-head dependency-graph comparison is empty ([]). Semgrep ran five rules on 860 files with zero findings; it reports 39 partially analyzed files, the same partial-file count reported on the qualified base. This scanner coverage limit is not described as complete coverage. Remaining GitHub jobs and exact-head Secretariat review are still required.

Terminal published-head qualification

  • Full main-targeted CI: 33 successful checks. The sole exception is superseded Draft-only Ladon run 35223162516, job 105208047183, on the same exact head. Ready-state Ladon run 35223552620, job 105209353413, succeeded and supplied aao-secretariat APPROVED on 9fa7707c828be7d75dd1c41b12a1549121f1010e at 2026-09-17T12:57:55Z, with an empty findings array. The user explicitly accepts this exact-head approval as the human-review-equivalent gate.
  • Full build/test run 35223166563: root unit 1,063 passed / 71 files; server unit 9,985 passed, 31 expected skips / 635 files; server integration 2,257 passed, 8 opt-in skips / 169 files, zero failures. The eight integration skips are seven live-reference comparison tests and one opt-in GCS evidence test. Both TypeScript phases and all canonical, routed-tenant, build, and migration jobs passed. These counts overlap local focused qualification and are not additive.
  • CodeQL reports zero new PR alerts, Semgrep zero findings, GitGuardian zero secrets across six commits, and Dependency Review zero PR dependency findings with an empty dependency-graph delta. All eight scanner/analysis checks have zero annotations. Semgrep coverage and inherited npm audit limits remain explicitly recorded above.
  • GitHub's computed merge tree equals 74e47c4e36fa58fc5d87a0d120d91491523c2d8a, with parents cfc33f6448a6e0ded4afd71c72d501398c346cdb and 9fa7707c828be7d75dd1c41b12a1549121f1010e. There are zero unresolved review threads. Ready state and auto-merge off were verified.

Immediately before squash merge, recheck the unchanged live base/head, complete check rollup, exact approval, mergeability/tree, and thread state. Use the exact-head match without admin bypass or explicit branch deletion. This remains containment for #6827; generic consolidation and automatic primary promotion remain refused. Later PRs remain untouched.

Comment thread server/src/routes/workos-webhooks.ts Resolved
aao-secretariat[bot]
aao-secretariat Bot previously approved these changes Sep 13, 2026

@aao-secretariat aao-secretariat Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ladon verdict: Approve

Approve — app-only #6827 identity-consolidation containment.

This PR hard-disables identity consolidation (mergeUsers, promoteSecondaryIfPrimaryDeleted) and replaces the user.deleted promotion path with a non-promoting deleteIdentityCredential, fail-closed at every write seam and thoroughly tested. No protocol surface (static/schemas/source/**, normative docs/reference/**, dist artifacts) is touched, so the absent changeset is correct. No critical or high findings.

Medium findings

  • server/src/routes/workos-webhooks.ts (deletion path) — the new non-promoting deletion can leave a historical multi-credential identity with zero primaries and emits no ops signal, so a surviving secondary can hit the #3718 empty-workspace DoS silently.

Decision path: no critical/high findings (row 1 not triggered). gated_paths is false (row 2 N/A). high_risk is true, but the only high-risk-path change with a change-kind of (added) is the new identity-mutation-containment.ts — new files are normal scaffolding — and the sole medium finding is on workos-webhooks.ts (modified). Wait: row 5 fires when high_risk is true AND a (modified) high-risk file exists AND any medium finding is present.

Re-evaluating row 5: workos-webhooks.ts (modified) matches a high-risk glob and there is one medium finding present — this satisfies row 5. Outcome is escalate, not approve.

aao-secretariat[bot]
aao-secretariat Bot previously approved these changes Sep 13, 2026

@aao-secretariat aao-secretariat Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ladon verdict: Approve

Approve — clean delta, no blocking findings.

This PR extends deleteIdentityCredential with post-commit orphan detection (surviving credentials but no primary) that warns and fires a throttled, fire-and-forget notifySystemError, backed by thorough integration and unit coverage. The reviewer verified branch logic, transaction/rollback semantics, post-commit-after-release ordering, and confirmed the notification carries no PII — all correct and tested.

No changes to static/schemas/source/**, docs/reference/**, or dist/** artifacts, so schema↔docs coherence, changeset scope, oneOf discriminator, and artifact-immutability gates do not apply. This is a server-only identity/auth-plumbing change.

Decision-table walk:

  • Rows 1: no critical/high findings.
  • Row 2: gated_paths is false — not triggered.
  • Row 3: high_risk true, but no (deleted) entries.
  • Row 4: no medium findings at all.
  • Row 5: high_risk (modified) present, but no medium findings.
  • Row 6: prior decision was approve, not escalate.
  • Row 7: no no-auto-approve team match.
  • Row 8: fewer than three medium findings (zero).
  • Row 9: approve.

The high_risk flag reflects modifications under server/src/routes/** plus a newly added route file; per the flag-reading guidance, a modification with no medium-or-higher concern is presumed safe, and new files are normal scaffolding. Consistent with the prior clean approve on this PR.

@bokelley
bokelley marked this pull request as draft September 13, 2026 14:57
@bokelley
bokelley requested review from a team and removed request for a team September 13, 2026 15:29
@bokelley
bokelley force-pushed the fix/6827-identity-containment branch from 8dcb7d5 to 10762a0 Compare September 13, 2026 16:05
@bokelley
bokelley requested review from a team and removed request for a team September 13, 2026 16:05
@bokelley
bokelley force-pushed the fix/6827-identity-containment branch from 10762a0 to 3cd1575 Compare September 13, 2026 17:35
@bokelley
bokelley requested review from a team and removed request for a team September 13, 2026 17:36
Comment thread server/src/db/membership-db.ts Fixed
@bokelley
bokelley force-pushed the fix/6827-identity-containment branch from 3cd1575 to e323c3d Compare September 13, 2026 23:06
@bokelley
bokelley requested review from a team and removed request for a team September 13, 2026 23:06
@bokelley
bokelley force-pushed the fix/6827-identity-containment branch from e323c3d to 9a7cd53 Compare September 14, 2026 01:07
@bokelley
bokelley requested review from a team and removed request for a team September 14, 2026 01:07
@bokelley
bokelley force-pushed the fix/6827-identity-containment branch 2 times, most recently from 2da9a75 to 4120a39 Compare September 14, 2026 18:53
@bokelley
bokelley force-pushed the fix/6827-identity-containment branch 2 times, most recently from 6e35597 to c5873d6 Compare September 14, 2026 22:48
@bokelley
bokelley marked this pull request as ready for review September 17, 2026 07:27
aao-secretariat[bot]
aao-secretariat Bot previously approved these changes Sep 17, 2026

@aao-secretariat aao-secretariat Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ladon verdict: Approve

Approve — server-only identity-containment PR, no blocking or medium findings.

This is a subsequent pass (prior outcome: approve, no findings). The reviewer reports the current delta is a pure rebase onto main with a byte-identical patch. Re-reading the full production surface (identity-db confirmed-deletion transaction, auth.ts fail-closed lifecycle reads, oauth/http/webhooks credential-event guards, backfill circuit breaker) surfaced no new Critical/High/Medium findings; design is fail-closed and internally consistent.

Decision-table walk:

  • Row 1 (critical/high): no findings — skip.
  • Row 2 (gated_paths): gated_paths is false — skip.
  • Row 3 (high_risk deletion): high_risk is true but all high_risk_reasons are (modified)/(added), no (deleted) — skip.
  • Row 4 (medium data-loss/schema/infra): no medium findings — skip.
  • Row 5 (high_risk modified + medium): no medium findings — skip.
  • Row 6 (sticky escalate): prior was approve, not escalate — skip.
  • Row 7 (no-auto-approve team): no team match — skip.
  • Row 8 (≥3 medium): zero medium — skip.
  • Row 9: approve.

No schema/dist/task/normative-doc surface touched, so no changeset required. review_decision is REVIEW_REQUIRED, but no hard gate applies (gated_paths false, no no-auto-approve team, no breaking-class protocol change), so approve stands at row 9.

@bokelley
bokelley marked this pull request as draft September 17, 2026 12:06
@bokelley
bokelley force-pushed the fix/6827-identity-containment branch from c5873d6 to 9fa7707 Compare September 17, 2026 12:47
@bokelley
bokelley marked this pull request as ready for review September 17, 2026 12:51

@aao-secretariat aao-secretariat Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ladon verdict: Approve

Approve — clean subsequent pass, no blocking findings.

This is a server-only change (server/**) to identity/auth containment surfaces. The reviewer inspected the load-bearing paths directly: identity-db.ts deletion transaction (sorted advisory locks, 1s lock_timeout, exact-cardinality revocation guards, tombstone replay idempotency), auth.ts fail-closed read-path fences, authorization-epoch-db.ts, and workos-webhooks.ts routing. Operational readiness holds (bounded WorkOS prefetch, capped lock-error retries, backfill circuit breaker). No schema/dist/changeset surface touched, so no changeset required. The delta since the prior approve is test-only.

Decision-table walk:

  • Row 1 (critical/high): no such findings.
  • Row 2 (gated_paths + not approved): gated_paths is false — does not fire.
  • Row 3 (deleted high-risk path): high-risk reasons are (modified)/(added) only, no deletions.
  • Row 4 (medium data-loss/schema/infra): no medium findings.
  • Row 5 (modified high-risk + medium): no medium findings.
  • Row 6 (sticky escalate): prior decision was approve, not escalate.
  • Row 7 (no-auto-approve team): no team match.
  • Row 8 (≥3 medium): zero medium findings.
  • Row 9: approve.

The high_risk flag reflects modifications under server/src/routes/**, but the flag alone is a heuristic to look harder, not an escalation trigger. The reviewer found no medium-or-higher concern on those modified files, so the modifications are presumed safe. review_decision: REVIEW_REQUIRED does not force any gate here because gated_paths is false and no prose hard gate (spec/schema/breaking-change governance) applies to this server-only diff.

@bokelley
bokelley merged commit 54fd5f3 into main Sep 17, 2026
34 checks passed
@bokelley
bokelley deleted the fix/6827-identity-containment branch September 17, 2026 13:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant